<?php
session_start();

// 检查用户是否已登录
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
    header('Location: login.php');
    exit;
}

class LogAnalyzer {
    private $logPath;
    private $results = [];

    public function __construct() {
        // 设置日志目录
        $this->logPath = __DIR__ . '/logs/';
        
        // 如果日志目录不存在，创建它
        if (!is_dir($this->logPath)) {
            if (mkdir($this->logPath, 0755, true)) {
                // 目录创建成功
            } else {
                // 目录创建失败
            }
        }

        // 检查软链接是否存在，如果不存在则创建
        $linkPath = $this->logPath . 'wwwlogs';
        if (!file_exists($linkPath)) {
            // 使用相对路径创建软链接
            $target = '../../wwwlogs'; // 确保目标路径在允许的范围内
            
            // 尝试创建软链接
            if (@symlink($target, $linkPath)) {
                // 软链接创建成功
            } else {
                // 软链接创建失败
                $error = error_get_last();
                if ($error) {
                    // 显示错误信息
                }
            }
        } else {
            if (is_link($linkPath)) {
                // 软链接已存在
            } else {
                // 警告：存在同名文件但不是软链接
            }
        }
        
        // 更新日志路径
        $this->logPath = $linkPath . '/';
    }

    public function analyze() {
        // 创建 shell 脚本
        $shellScript = __DIR__ . '/log_analyzer.sh';
        $this->createShellScript($shellScript);

        // 通过 shell 脚本读取日志
        $cmd = "sh " . escapeshellarg($shellScript) . " read";
        $output = shell_exec($cmd);
        
        // 解析输出
        if ($output) {
            $this->parseResults($output);
        } else {
            // 无法获取日志信息
        }
    }

    private function createShellScript($scriptPath) {
        $script = <<<'EOT'
#!/bin/bash
LOG_DIR="/www/wwwlogs"
ACTION=$1

case $ACTION in
    "read")
        # 获取所有日志文件
        for logfile in $LOG_DIR/*.log; do
            if [ -f "$logfile" ]; then
                filename=$(basename "$logfile")
                site=${filename%.log}
                
                echo "=== $site ==="
                # 总请求数
                echo "Requests: $(wc -l < "$logfile")"
                
                # 状态码统计
                echo "Status Codes:"
                awk '{print $9}' "$logfile" | sort | uniq -c | sort -rn
                
                # Top 20 IPs with UA
                echo "Top IPs:"
                awk '{ip=$1; ua=""; for(i=12;i<=NF;i++) ua=ua" "$i; print ip "\t" ua}' "$logfile" | sort | uniq -c | sort -rn | head -n 20
                
                # 为每个Top IP获取状态码统计和完整日志
                echo "IP Details:"
                for ip in $(awk '{print $1}' "$logfile" | sort | uniq -c | sort -rn | head -n 20 | awk '{print $2}'); do
                    echo "IP:$ip"
                    # 状态码统计
                    echo "STATUS_CODES:$ip"
                    awk -v target_ip="$ip" '$1==target_ip {print $9}' "$logfile" | sort | uniq -c | sort -rn
                    # 该IP的所有日志
                    echo "ALL_LOGS:$ip"
                    awk -v target_ip="$ip" '$1==target_ip {print $0}' "$logfile"
                    echo "END_IP:$ip"
                done
                
                # 总流量
                echo "Traffic:"
                awk '{sum+=$10} END {print sum}' "$logfile"
                
                # 最后访问时间
                echo "Last Access:"
                tail -n 1 "$logfile" | awk '{print $4}'
                
                # 每个 Top 20 IP 访问最多的 3 个页面
                echo "Top Pages per IP:"
                for ip in $(awk '{print $1}' "$logfile" | sort | uniq -c | sort -rn | head -n 20 | awk '{print $2}'); do
                    awk -v target_ip="$ip" '$1==target_ip {print $1, $7}' "$logfile" | sort | uniq -c | sort -rn | head -n 3
                done
                
                # 最新的100条日志记录（倒序，最新的在前面）
                echo "Latest Logs:"
                tail -n 100 "$logfile" | tac
                
                echo "=== END $site ==="
            fi
        done
        ;;
    *)
        echo "Unknown action: $ACTION"
        exit 1
        ;;
esac
EOT;

        file_put_contents($scriptPath, $script);
        chmod($scriptPath, 0755);
    }

    private function parseResults($output) {
        $lines = explode("\n", $output);
        $currentSite = null;
        $section = null;
        $currentIP = null; # 用于追踪当前处理的IP
        $currentTopIP = null; # 用于追踪Top IPs部分当前处理的IP

        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line)) continue;

            // 检查是否是网站开始标记
            if (preg_match('/=== (.*?) ===/', $line, $matches)) {
                if ($matches[1] != 'END') {
                    $currentSite = $matches[1];
                    $this->results[$currentSite] = [
                        'total_requests' => 0,
                        'status_codes' => [],
                        'top_ips' => [],
                        'traffic' => 0,
                        'last_access' => '',
                        'top_pages_per_ip' => [],
                        'latest_logs' => [],
                        'ip_details' => [] # 存储每个IP的详细信息
                    ];
                } else {
                    # 网站结束，重置变量
                    $currentTopIP = null;
                }
                continue;
            }

            // 解析各个部分
            if (strpos($line, 'Requests:') === 0) {
                $this->results[$currentSite]['total_requests'] = (int)substr($line, 9);
            }
            elseif ($line == 'Status Codes:') {
                $section = 'status_codes';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'Top IPs:') {
                $section = 'top_ips';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'Traffic:') {
                $section = 'traffic';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'Last Access:') {
                $section = 'last_access';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'Top Pages per IP:') {
                $section = 'top_pages_per_ip';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'Latest Logs:') {
                $section = 'latest_logs';
                $currentTopIP = null; # 重置当前TopIP
            }
            elseif ($line == 'IP Details:') {
                $section = 'ip_details';
                # 不重置$currentTopIP，因为后面还需要用到
            }
            elseif (preg_match('/^IP:(.+)$/', $line, $matches)) {
                $currentIP = $matches[1];
                $this->results[$currentSite]['ip_details'][$currentIP] = [
                    'status_codes' => [],
                    'all_logs' => []
                ];
                $section = 'ip_processing';
            }
            elseif (preg_match('/^STATUS_CODES:(.+)$/', $line, $matches)) {
                $currentIP = $matches[1];
                $section = 'ip_status_codes';
            }
            elseif (preg_match('/^ALL_LOGS:(.+)$/', $line, $matches)) {
                $currentIP = $matches[1];
                $section = 'ip_all_logs';
            }
            elseif (preg_match('/^END_IP:(.+)$/', $line, $matches)) {
                $section = null;
                $currentIP = null;
            }
            elseif ($currentSite && $section) {
                switch ($section) {
                    case 'status_codes':
                        if (preg_match('/^\s*(\d+)\s+(.*)$/', $line, $matches)) {
                            $this->results[$currentSite][$section][$matches[2]] = (int)$matches[1];
                        }
                        break;
                    case 'top_ips':
                        if (preg_match('/^\s*(\d+)\s+(\S+)\s+(.*)$/', $line, $matches)) {
                            $count = (int)$matches[1];
                            $ip = $matches[2];
                            $ua = trim($matches[3]);
                            $this->results[$currentSite][$section][$ip] = [
                                'count' => $count,
                                'ua' => $ua
                            ];
                        }
                        break;
                    case 'traffic':
                        $this->results[$currentSite]['traffic'] = $this->formatBytes((int)$line);
                        break;
                    case 'last_access':
                        $this->results[$currentSite]['last_access'] = trim($line, '[]');
                        break;
                    case 'top_pages_per_ip':
                        if (preg_match('/^\s*(\d+)\s+(\S+)\s+(.*)$/', $line, $matches)) {
                            $ip = $matches[2];
                            $url = $matches[3];
                            $count = (int)$matches[1];
                            if (!isset($this->results[$currentSite]['top_pages_per_ip'][$ip])) {
                                $this->results[$currentSite]['top_pages_per_ip'][$ip] = [];
                            }
                            if (count($this->results[$currentSite]['top_pages_per_ip'][$ip]) < 3) {
                                $this->results[$currentSite]['top_pages_per_ip'][$ip][] = [
                                    'url' => $url,
                                    'count' => $count
                                ];
                            }
                        }
                        break;
                    case 'latest_logs':
                        if (!empty($line)) {
                            $this->results[$currentSite]['latest_logs'][] = $line;
                        }
                        break;
                    case 'ip_status_codes':
                        if (preg_match('/^\s*(\d+)\s+(.*)$/', $line, $matches) && isset($currentIP)) {
                            $this->results[$currentSite]['ip_details'][$currentIP]['status_codes'][$matches[2]] = (int)$matches[1];
                        }
                        break;
                    case 'ip_all_logs':
                        if (!empty($line) && isset($currentIP)) {
                            $this->results[$currentSite]['ip_details'][$currentIP]['all_logs'][] = $line;
                        }
                        break;
                }
            }
        }

        $this->displayResults();
    }

    private function formatBytes($bytes) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);
        return round($bytes, 2) . ' ' . $units[$pow];
    }

    private function displayResults() {
        // 输出 HTML 头部
        $this->outputHeader();
        
        echo '<div class="container-fluid">';
        echo '<h1 class="mb-4 mt-3">小铭宝塔网站日志分析系统</h1>';
        
        echo '<div class="row">';
        // 左侧网站列表
        echo '<div class="col-md-2">';
        echo '<div class="list-group">';

        // 根据请求数量对网站列表进行排序
        uasort($this->results, function($a, $b) {
            return $b['total_requests'] - $a['total_requests'];
        });

        foreach ($this->results as $site => $data) {
            // 跳过包含 error 的日志文件或请求数为 0 的日志
            if (strpos($site, 'error') !== false || $data['total_requests'] == 0) continue;
            
            $siteId = md5($site); // 使用md5生成唯一ID
            echo "<a href='#' class='list-group-item list-group-item-action' data-site-id='{$siteId}'>";
            echo "<div class='d-flex justify-content-between align-items-center'>";
            echo "<span>{$site}</span>";
            echo "<span class='badge bg-primary rounded-pill'>{$data['total_requests']}</span>";
            echo "</div>";
            echo "</a>";
        }
        echo '</div>';
        echo '</div>';
        
        // 右侧数据展示
        echo '<div class="col-md-10">';
        // 输出每个网站的数据
        foreach ($this->results as $site => $data) {
            // 跳过包含 error 的日志文件或请求数为 0 的日志
            if (strpos($site, 'error') !== false || $data['total_requests'] == 0) continue;
            
            $siteId = md5($site); // 使用相同的md5生成唯一ID
            echo "<div class='site-data' data-site-id='{$siteId}' style='display:none;'>";
            
            // 基础信息卡片
            echo "<div class='row mb-4'>";
            echo "<div class='col-md-4'>";
            echo "<div class='card h-100'>";
            echo "<div class='card-body text-center'>";
            echo "<h5 class='card-title'>总请求数</h5>";
            echo "<h2 class='card-text'>{$data['total_requests']}</h2>";
            echo "</div></div></div>";
            
            echo "<div class='col-md-4'>";
            echo "<div class='card h-100'>";
            echo "<div class='card-body text-center'>";
            echo "<h5 class='card-title'>总流量</h5>";
            echo "<h2 class='card-text'>{$data['traffic']}</h2>";
            echo "</div></div></div>";
            
            echo "<div class='col-md-4'>";
            echo "<div class='card h-100'>";
            echo "<div class='card-body text-center'>";
            echo "<h5 class='card-title'>最后访问</h5>";
            echo "<h2 class='card-text'>{$data['last_access']}</h2>";
            echo "</div></div></div>";
            echo "</div>";
            
            // 状态码统计
            echo "<div class='card mb-4'>";
            echo "<div class='card-header bg-info text-white'><h5 class='mb-0'>状态码统计</h5></div>";
            echo "<div class='card-body'>";
            echo "<div class='table-responsive'>";
            echo "<table class='table table-striped table-hover'>";
            echo "<thead><tr><th>状态码</th><th>次数</th><th>占比</th></tr></thead><tbody>";
            foreach ($data['status_codes'] as $code => $count) {
                $percentage = round(($count / $data['total_requests']) * 100, 2);
                $colorClass = $this->getStatusCodeColor($code);
                echo "<tr>";
                echo "<td><span class='badge {$colorClass}'>{$code}</span></td>";
                echo "<td>{$count}</td>";
                echo "<td>";
                echo "<div class='progress'>";
                echo "<div class='progress-bar {$colorClass}' role='progressbar' style='width: {$percentage}%'>";
                echo "{$percentage}%";
                echo "</div></div>";
                echo "</td>";
                echo "</tr>";
            }
            echo "</tbody></table>";
            echo "</div></div></div>";
            
            // IP统计和URL统计并排显示
            echo "<div class='row'>";
            // IP统计
            echo "<div class='col-md-12'>"; // 修改为占据整行
            echo "<div class='card mb-4'>";
            echo "<div class='card-header bg-success text-white'><h5 class='mb-0'>访问最多的IP (前20)</h5></div>";
            echo "<div class='card-body'>";
            echo "<div class='table-responsive'>";
            echo "<table class='table table-striped table-hover'>";
            echo "<thead><tr><th style='width: 8.334%'>IP地址</th><th style='width: 8.33%'>访问次数</th><th style='width: 8.33%'>状态码统计</th><th style='width: 50%'>User Agent</th><th style='width: 25%'>访问最多的页面</th></tr></thead><tbody>";
            foreach ($data['top_ips'] as $ip => $info) {
                $topPages = isset($data['top_pages_per_ip'][$ip]) ? $data['top_pages_per_ip'][$ip] : [];
                $ipDetails = isset($data['ip_details'][$ip]) ? $data['ip_details'][$ip] : [];
                echo "<tr>";
                echo "<td><a href='javascript:void(0)' class='text-decoration-none' onclick='showIPLogs(\"{$ip}\", \"{$siteId}\", event)' title='点击查看详细日志'>{$ip}</a></td>";
                echo "<td>{$info['count']}</td>";
                echo "<td>";
                if (!empty($ipDetails['status_codes'])) {
                    echo "<div class='d-flex flex-wrap gap-1'>";
                    foreach ($ipDetails['status_codes'] as $code => $count) {
                        $colorClass = $this->getStatusCodeColor($code);
                        echo "<span class='badge {$colorClass}' title='状态码{$code}: {$count}次'>{$code}: {$count}</span>";
                    }
                    echo "</div>";
                } else {
                    echo "无数据";
                }
                echo "</td>";
                echo "<td class='text-break'>{$info['ua']}</td>";
                echo "<td>";
                if (!empty($topPages)) {
                    echo "<ul class='list-unstyled mb-0'>";
                    foreach ($topPages as $page) {
                        echo "<li class='text-break'>{$page['url']} ({$page['count']} 次)</li>";
                    }
                    echo "</ul>";
                } else {
                    echo "无数据";
                }
                echo "</td>";
                echo "</tr>";
            }
            echo "</tbody></table>";
            echo "</div></div></div>";
            echo "</div>";
            
            // 最新日志记录
            echo "<div class='card mb-4'>";
            echo "<div class='card-header bg-info text-white'><h5 class='mb-0'>最新日志记录 (最近100条)</h5></div>";
            echo "<div class='card-body p-0'>"; // 移除内边距使内容更紧凑
            echo "<div style='overflow-x: auto;'>";
            foreach ($data['latest_logs'] as $log) {
                echo "<div style='white-space: nowrap; padding: 4px 15px; border-bottom: 1px solid #eee;'>";
                echo htmlspecialchars($log);
                echo "</div>";
            }
            echo "</div></div></div>";
            
            echo "</div>";
            echo "</div>";
        }
        echo '</div>'; // 结束 col-md-10
        echo '</div>'; // 结束 row
        echo '</div>'; // 结束 container-fluid
        
        // 输出IP详情数据到JavaScript
        $this->outputIPDetailsScript();
        
        // 输出 HTML 底部
        $this->outputFooter();
    }

    private function outputHeader() {
        $username = htmlspecialchars($_SESSION['username']);
        echo <<<HTML
<!DOCTYPE html>
<html lang="zh" data-bs-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小铭宝塔网站日志分析系统</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.1/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.bootcdn.net/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css" rel="stylesheet">
    <style>
        .site-data { display: none; }
        .text-break { word-break: break-all; }
        .progress { height: 20px; }
        .progress-bar { line-height: 20px; }
        .list-group-item { cursor: pointer; }
        .list-group-item:hover { background-color: var(--bs-tertiary-bg); }
        .list-group-item.active { background-color: var(--bs-primary); border-color: var(--bs-primary); }
        .table-hover tbody tr:hover { background-color: var(--bs-tertiary-bg); }
        
        /* 暗夜模式特定样式 */
        [data-bs-theme="dark"] {
            --bs-body-bg: #1a1d20;
            --bs-body-color: #e1e1e1;
        }
        
        /* 主题切换按钮样式 */
        .theme-toggle {
            cursor: pointer;
            padding: 5px 10px;
            border-radius: 4px;
            margin-right: 15px;
        }
        .theme-toggle:hover {
            background-color: var(--bs-tertiary-bg);
        }
        .theme-toggle i {
            font-size: 1.2rem;
        }
        
        /* IP日志弹窗样式 */
        .ip-modal {
            display: none;
            position: fixed;
            z-index: 1060;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
        }
        .ip-modal-content {
            background-color: var(--bs-body-bg);
            margin: 2% auto;
            padding: 20px;
            border-radius: 8px;
            width: 95%;
            max-height: 90%;
            overflow-y: auto;
        }
        .ip-modal .close {
            color: var(--bs-body-color);
            float: right;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
        }
        .ip-modal .close:hover {
            opacity: 0.7;
        }
        .log-entry {
            font-family: 'Courier New', monospace;
            font-size: 12px;
            padding: 4px 8px;
            border-bottom: 1px solid var(--bs-border-color);
            white-space: nowrap;
            min-width: max-content;
        }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">小铭宝塔网站日志分析系统</a>
            <div class="ms-auto d-flex align-items-center">
                <div class="theme-toggle text-light" onclick="toggleTheme()" title="切换主题">
                    <i class="bi bi-sun-fill" id="themeIcon"></i>
                </div>
                <span class="text-light me-3">欢迎，{$username}</span>
                <a href="logout.php" class="btn btn-outline-light">退出</a>
            </div>
        </div>
    </nav>
    
    <!-- IP日志弹窗 -->
    <div id="ipModal" class="ip-modal">
        <div class="ip-modal-content">
            <span class="close" onclick="closeIPModal()">&times;</span>
            <h4 id="ipModalTitle">IP详细日志</h4>
            <div id="ipModalContent">
                <div class="text-center">
                    <div class="spinner-border" role="status">
                        <span class="visually-hidden">加载中...</span>
                    </div>
                </div>
            </div>
        </div>  
    </div>
HTML;
    }

    private function outputIPDetailsScript() {
        echo '<script>';
        echo 'var ipDetailsData = ' . json_encode($this->results, JSON_UNESCAPED_UNICODE) . ';';
        echo '</script>';
    }

    private function outputFooter() {
        echo <<<HTML
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.1/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script>
    // 主题切换功能
    function toggleTheme() {
        const html = document.documentElement;
        const themeIcon = document.getElementById('themeIcon');
        const currentTheme = html.getAttribute('data-bs-theme');
        const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
        
        html.setAttribute('data-bs-theme', newTheme);
        themeIcon.className = newTheme === 'dark' ? 'bi bi-moon-fill' : 'bi bi-sun-fill';
        
        // 保存主题偏好
        localStorage.setItem('theme', newTheme);
    }

    // 页面加载时应用保存的主题
    document.addEventListener('DOMContentLoaded', function() {
        const savedTheme = localStorage.getItem('theme') || 'light';
        const html = document.documentElement;
        const themeIcon = document.getElementById('themeIcon');
        
        html.setAttribute('data-bs-theme', savedTheme);
        themeIcon.className = savedTheme === 'dark' ? 'bi bi-moon-fill' : 'bi bi-sun-fill';
        
        // 为所有网站列表项添加点击事件
        document.querySelectorAll('.list-group-item').forEach(item => {
            item.addEventListener('click', function(e) {
                e.preventDefault();
                const siteId = this.getAttribute('data-site-id');
                showSite(siteId);
            });
        });
        
        // 自动选择第一个网站
        const firstSite = document.querySelector('.list-group-item');
        if (firstSite) {
            const siteId = firstSite.getAttribute('data-site-id');
            if (siteId) {
                showSite(siteId);
            }
        }
    });
    
    function showSite(siteId) {
        if (!siteId) return;
        
        // 隐藏所有网站数据
        document.querySelectorAll('.site-data').forEach(el => el.style.display = 'none');
        
        // 移除所有活动状态
        document.querySelectorAll('.list-group-item').forEach(el => el.classList.remove('active'));
        
        // 显示选中的网站数据
        const siteElement = document.querySelector('.site-data[data-site-id="' + siteId + '"]');
        const listItem = document.querySelector('.list-group-item[data-site-id="' + siteId + '"]');
        
        if (siteElement && listItem) {
            siteElement.style.display = 'block';
            listItem.classList.add('active');
        }
    }
    
    // IP弹窗相关函数
    function showIPLogs(ip, siteId, event) {
        // 阻止默认事件，防止页面滚动
        if (event) {
            event.preventDefault();
            event.stopPropagation();
        }
        
        if (!ipDetailsData || !ip) {
            alert('数据未加载或IP无效');
            return;
        }
        
        // 直接遍历所有网站数据查找该IP的详细信息
        let ipData = null;
        let siteName = '';
        
        for (let site in ipDetailsData) {
            if (ipDetailsData[site].ip_details && ipDetailsData[site].ip_details[ip]) {
                ipData = ipDetailsData[site].ip_details[ip];
                siteName = site;
                break;
            }
        }
        
        if (!ipData) {
            alert('找不到该IP的详细日志数据，可能数据还在加载中');
            console.log('可用的IP详情数据:', ipDetailsData);
            return;
        }
        
        const modal = document.getElementById('ipModal');
        const title = document.getElementById('ipModalTitle');
        const content = document.getElementById('ipModalContent');
        
        title.textContent = 'IP: ' + ip + ' 的详细日志 (网站: ' + siteName + ')';
        
        let html = '<div class="mb-3">';
        html += '<h6>状态码统计:</h6>';
        if (ipData.status_codes && Object.keys(ipData.status_codes).length > 0) {
            html += '<div class="d-flex flex-wrap gap-2 mb-3">';
            for (let code in ipData.status_codes) {
                const count = ipData.status_codes[code];
                const colorClass = getStatusCodeColor(code);
                html += '<span class="badge ' + colorClass + '">状态码 ' + code + ': ' + count + ' 次</span>';
            }
            html += '</div>';
        } else {
            html += '<p class="text-muted">无状态码数据</p>';
        }
        
        html += '<h6>所有访问日志 (共 ' + (ipData.all_logs ? ipData.all_logs.length : 0) + ' 条):</h6>';
        html += '<div style="overflow-y: auto; overflow-x: auto; border: 1px solid var(--bs-border-color); border-radius: 4px;">';
        
        if (ipData.all_logs && ipData.all_logs.length > 0) {
            ipData.all_logs.forEach(function(log) {
                html += '<div class="log-entry">' + escapeHtml(log) + '</div>';
            });
        } else {
            html += '<div class="text-center p-3 text-muted">无日志数据</div>';
        }
        
        html += '</div></div>';
        content.innerHTML = html;
        modal.style.display = 'block';
    }
    
    function closeIPModal() {
        document.getElementById('ipModal').style.display = 'none';
    }
    
    function getStatusCodeColor(code) {
        if (!code || !/^\d/.test(code)) return 'bg-secondary';
        if (code.charAt(0) === '2') return 'bg-success';
        if (code.charAt(0) === '3') return 'bg-info'; 
        if (code.charAt(0) === '4') return 'bg-warning';
        if (code.charAt(0) === '5') return 'bg-danger';
        return 'bg-secondary';
    }
    
    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
    
    // 点击弹窗外部关闭
    window.onclick = function(event) {
        const modal = document.getElementById('ipModal');
        if (event.target === modal) {
            closeIPModal();
        }  
    }
    
    // ESC键关闭弹窗
    document.addEventListener('keydown', function(event) {
        if (event.key === 'Escape' || event.keyCode === 27) {
            const modal = document.getElementById('ipModal');
            if (modal && modal.style.display === 'block') {
                closeIPModal();
            }
        }
    });
    </script>
</body>
</html>
HTML;
    }

    private function getStatusCodeColor($code) {
        if (!is_numeric($code)) return 'bg-secondary';
        if (strpos($code, '2') === 0) return 'bg-success';
        if (strpos($code, '3') === 0) return 'bg-info';
        if (strpos($code, '4') === 0) return 'bg-warning';
        if (strpos($code, '5') === 0) return 'bg-danger';
        return 'bg-secondary';
    }
}

// 设置错误报告（仅在开发环境中启用）
if (getenv('APP_ENV') === 'development') {
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
} else {
    error_reporting(0);
    ini_set('display_errors', 0);
}

// 错误处理
try {
    $analyzer = new LogAnalyzer();
    $analyzer->analyze();
} catch (Exception $e) {
    // 记录错误日志
    error_log($e->getMessage());
    // 显示友好的错误信息
    echo '<div class="alert alert-danger">抱歉，系统暂时无法处理您的请求。请稍后再试。</div>';
}
?>